﻿#region Copyright
//
// Copyright (C) 2010-2012 by Autodesk, Inc.
//
// Permission to use, copy, modify, and distribute this software in
// object code form for any purpose and without fee is hereby granted,
// provided that the above copyright notice appears in all copies and
// that both that copyright notice and the limited warranty and
// restricted rights notice below appear in all supporting
// documentation.
//
// AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.
// AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF
// MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
// DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE
// UNINTERRUPTED OR ERROR FREE.
//
// Use, duplication, or disclosure by the U.S. Government is subject to
// restrictions set forth in FAR 52.227-19 (Commercial Computer
// Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii)
// (Rights in Technical Data and Computer Software), as applicable.
//
// Migrated to C# by Saikat Bhattacharya
// 
#endregion // Copyright

#region Namespaces
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Media.Imaging;
using Autodesk.Revit.ApplicationServices;
using Autodesk.Revit.Attributes;
using Autodesk.Revit.DB;
using Autodesk.Revit.UI;
#endregion

namespace UiCs
{
    /// <summary>
    /// Ribbon UI. 
    /// we'll be using commands we defined in Revit Intro labs. alternatively, 
    /// you can use your own. Any command will do for this ribbon exercise. 
    /// cf. Developer Guide, Section 3.8: Ribbon Panels and Controls. (pp 46). 
    /// </summary>
    [Transaction(TransactionMode.Automatic)]
    public class UIRibbon : IExternalApplication
    {
        /// <summary>
        /// This is both the assembly name and the namespace 
        /// of the external command provider.
        /// </summary>
        const string _introLabName = "IntroCs";
        const string _uiLabName = "UiCs";
        const string _dllExtension = ".dll";

        /// <summary>
        /// Name of subdirectory containing images.
        /// </summary>
        const string _imageFolderName = "Images";

        /// <summary>
        /// Location of managed dll where we have defined the commands.
        /// </summary>
        string _introLabPath;
        string _nameCmd;

        /// <summary>
        /// Location of images for icons.
        /// </summary>
        string _imageFolder;

        /// <summary>
        /// Starting at the given directory, search upwards for 
        /// a subdirectory with the given target name located
        /// in some parent directory. 
        /// </summary>
        /// <param name="path">Starting directory, e.g. GetDirectoryName( GetExecutingAssembly().Location ).</param>
        /// <param name="target">Target subdirectory name, e.g. "Images".</param>
        /// <returns>The full path of the target directory if found, else null.</returns>
        string FindFolderInParents(string path, string target)
        {
            Debug.Assert(Directory.Exists(path),
              "expected an existing directory to start search in");

            string s;

            do
            {
                s = Path.Combine(path, target);
                if (Directory.Exists(s))
                {
                    return s;
                }
                path = Path.GetDirectoryName(path);
            } while (null != path);

            return null;
        }

        /// <summary>
        /// Load a new icon bitmap from our image folder.
        /// </summary>
        BitmapImage NewBitmapImage(string imageName)
        {
            return new BitmapImage(new Uri(
              Path.Combine(_imageFolder, imageName)));
        }

        /// <summary>
        /// OnShutdown() - called when Revit ends. 
        /// </summary>
        public Result OnShutdown(UIControlledApplication app)
        {
            return Result.Succeeded;
        }

        /// <summary>
        /// OnStartup() - called when Revit starts. 
        /// </summary>
        public Result OnStartup(UIControlledApplication app)
        {
            // External application directory:

            //string dir = Path.GetDirectoryName(
            //  System.Reflection.Assembly
            //  .GetExecutingAssembly().Location);

            // External command path:

            //_introLabPath = Path.Combine(dir, _introLabName + _dllExtension);

            //if (!File.Exists(_introLabPath))
            //{
            //    TaskDialog.Show("UIRibbon", "External command assembly not found: " + _introLabPath);
            //    return Result.Failed;
            //}

            //// Image path:

            //_imageFolder = FindFolderInParents(dir, _imageFolderName);

            //if (null == _imageFolder
            //  || !Directory.Exists(_imageFolder))
            //{
            //    TaskDialog.Show(
            //      "UIRibbon",
            //      string.Format(
            //        "No image folder named '{0}' found in the parent directories of '{1}.",
            //        _imageFolderName, dir));

            //    return Result.Failed;
            //}

            _imageFolder = @"D:\YJK_WORK\git_revit2\run\x64\Revit\Trans\LargeImage\安防快模.png";
            _introLabPath = @"D:\YJK_WORK\git_revit2\run\x64\Revit\Trans\program_hyarch2019\YJKWndrStatisticsExcel.dll";
            _nameCmd = "YJKWndrStatisticsExcel.FastStatisticTable.CmdFastStatisticTable";
            // Show what kind of custom buttons and controls 
            // we can add to the Add-Ins tab 

            AddRibbonSampler(app);

            // Add one for UI Labs, too. 

            AddUILabsButtons(app);

            return Result.Succeeded;
        }

        /// <summary>
        /// Create our own ribbon panel with verious buttons 
        /// for our exercise. We re-use commands defined in the
        /// Revit Intro Labs here. Cf. Section 3.8 (pp 46) of 
        /// the Developers Guide. 
        /// </summary>
        public void AddRibbonSampler(UIControlledApplication app)
        {
            // (1) create a ribbon tab and ribbon panel 

            app.CreateRibbonTab("Ribbon Sampler");

            RibbonPanel panel = app.CreateRibbonPanel("Ribbon Sampler", "Ribbon Sampler");

            // Below are samplers of ribbon items. Uncomment 
            // functions of your interest to see how it looks like 

            // (2.1) add a simple push button for Hello World 

            AddPushButton(panel);

            // (2.2) add split buttons for "Command Data", "DB Element" and "Element Filtering" 

            AddSplitButton(panel);

            // (2.3) add pulldown buttons for "Command Data", "DB Element" and "Element Filtering" 

            AddPulldownButton(panel);

            // (2.4) add radio/toggle buttons for "Command Data", "DB Element" and "Element Filtering" 
            // we put it on the slide-out below. 
            //AddRadioButton(panel);
            //panel.AddSeparator();

            // (2.5) add text box - TBD: this is used with the conjunction with event. Probably too complex for day one training. 
            //  for now, without event. 
            // we put it on the slide-out below. 
            //AddTextBox(panel);
            //panel.AddSeparator();

            // (2.6) combo box - TBD: this is used with the conjunction with event. Probably too complex for day one training. 
            // For now, without event. show two groups: Element Bascis (3 push buttons) and Modification/Creation (2 push button)  

            AddComboBox(panel);

            // (2.7) stacked items - 1. hello world push button, 2. pulldown element bscis (command data, DB element, element filtering) 
            // 3. pulldown modification/creation(element modification, model creation). 

            AddStackedButtons_Complex(panel);

            // (2.8) slide out - if you don't have enough space, you can add additional space below the panel. 
            // anything which comes after this will be on the slide out. 

            panel.AddSlideOut();

            // (2.4) radio button - what it is 

            AddRadioButton(panel);

            // (2.5) text box - what it is 

            AddTextBox(panel);
        }

        /// <summary>
        /// We create our own buttons for UI Labs, too. 
        /// cf. Section 3.8 (pp 46) of Developer Guide. 
        /// </summary>
        public void AddUILabsButtons(UIControlledApplication app)
        {
            // Create a ribbon panel 

            RibbonPanel panel = app.CreateRibbonPanel("UI Labs");

            // (3) adding buttons for the current labs itself. 
            // You may modify this AFTER each command are defined in each lab. 
            //AddUILabsCommandButtons_Template(panel) ' dummy 

            AddUILabsCommandButtons(panel);

            // (4) This is for Lab4 event and dynamic update. 

            AddUILabsCommandButtons2(panel);
        }

        /// <summary>
        /// Simple push button for "Hello World" 
        /// </summary>
        public void AddPushButton(RibbonPanel panel)
        {
            // Set the information about the command we will be assigning to the button 

            PushButtonData pushButtonDataHello = new PushButtonData("PushButtonHello", "Hello World", _introLabPath, _nameCmd);

            // Add a button to the panel 

            PushButton pushButtonHello = panel.AddItem(pushButtonDataHello) as PushButton;

            // Add an icon 
            // Make sure you reference WindowsBase and PresentationCore, and import System.Windows.Media.Imaging namespace. 

            pushButtonHello.LargeImage = NewBitmapImage(_imageFolder);

            // Add a tooltip 

            pushButtonHello.ToolTip = "simple push button";
        }

        /// <summary>
        /// Split button for "Command Data", "DB Element" and "Element Filtering" 
        /// </summary>
        public void AddSplitButton(RibbonPanel panel)
        {
            // Create three push buttons for split button drop down 

            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("SplitCommandData", "Command Data", _introLabPath, _nameCmd);
            pushButtonData1.LargeImage = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("SplitDbElement", "DB Element", _introLabPath, _nameCmd);
            pushButtonData2.LargeImage = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("SplitElementFiltering", "ElementFiltering", _introLabPath, _nameCmd);
            pushButtonData3.LargeImage = NewBitmapImage(_imageFolder);

            // Make a split button now 
            SplitButtonData splitBtnData = new SplitButtonData("SplitButton", "Split Button");
            SplitButton splitBtn = panel.AddItem(splitBtnData) as SplitButton;
            splitBtn.AddPushButton(pushButtonData1);
            splitBtn.AddPushButton(pushButtonData2);
            splitBtn.AddPushButton(pushButtonData3);
        }

        /// <summary>
        /// Pulldown button for "Command Data", "DB Element" and "Element Filtering"
        /// </summary>
        public void AddPulldownButton(RibbonPanel panel)
        {
            // Create three push buttons for pulldown button drop down 

            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("PulldownCommandData", "Command Data", _introLabPath, _nameCmd);
            pushButtonData1.LargeImage = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("PulldownDbElement", "DB Element", _introLabPath, _nameCmd);
            pushButtonData2.LargeImage = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("PulldownElementFiltering", "Filtering", _introLabPath, _nameCmd);
            pushButtonData3.LargeImage = NewBitmapImage(_imageFolder);

            // Make a pulldown button now 
            PulldownButtonData pulldownBtnData = new PulldownButtonData("PulldownButton", "Pulldown");
            PulldownButton pulldownBtn = panel.AddItem(pulldownBtnData) as PulldownButton;
            pulldownBtn.AddPushButton(pushButtonData1);
            pulldownBtn.AddPushButton(pushButtonData2);
            pulldownBtn.AddPushButton(pushButtonData3);
        }

        /// <summary>
        /// Radio/toggle button for "Command Data", "DB Element" and "Element Filtering"
        /// </summary>
        public void AddRadioButton(RibbonPanel panel)
        {
            // Create three toggle buttons for radio button group 

            // #1 
            ToggleButtonData toggleButtonData1 = new ToggleButtonData("RadioCommandData", "Command" + "\n Data", _introLabPath, _nameCmd);
            toggleButtonData1.LargeImage = NewBitmapImage(_imageFolder);

            // #2 
            ToggleButtonData toggleButtonData2 = new ToggleButtonData("RadioDbElement", "DB" + "\n Element", _introLabPath, _nameCmd);
            toggleButtonData2.LargeImage = NewBitmapImage(_imageFolder);

            // #3 
            ToggleButtonData toggleButtonData3 = new ToggleButtonData("RadioElementFiltering", "Filtering", _introLabPath, _nameCmd);
            toggleButtonData3.LargeImage = NewBitmapImage(_imageFolder);

            // Make a radio button group now 
            RadioButtonGroupData radioBtnGroupData = new RadioButtonGroupData("RadioButton");
            RadioButtonGroup radioBtnGroup = panel.AddItem(radioBtnGroupData) as RadioButtonGroup;
            radioBtnGroup.AddItem(toggleButtonData1);
            radioBtnGroup.AddItem(toggleButtonData2);
            radioBtnGroup.AddItem(toggleButtonData3);
        }

        /// <summary>
        /// Text box 
        /// Text box used in conjunction with event. We'll come to this later. 
        /// For now, just shows how to make a text box. 
        /// </summary>
        public void AddTextBox(RibbonPanel panel)
        {
            // Fill the text box information 
            TextBoxData txtBoxData = new TextBoxData("TextBox");
            txtBoxData.Image = NewBitmapImage(_imageFolder);
            txtBoxData.Name = "Text Box";
            txtBoxData.ToolTip = "Enter text here";
            txtBoxData.LongDescription = "<p>This is Revit UI Labs.</p><p>Ribbon Lab</p>";
            txtBoxData.ToolTipImage = NewBitmapImage(_imageFolder);

            // Create the text box item on the panel 
            TextBox txtBox = panel.AddItem(txtBoxData) as TextBox;
            txtBox.PromptText = "Enter a comment";
            txtBox.ShowImageAsButton = true;

            txtBox.EnterPressed += new EventHandler<Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs>(txtBox_EnterPressed);
            txtBox.Width = 180;
        }

        /// <summary>
        /// Event handler for the above text box 
        /// </summary>
        void txtBox_EnterPressed(object sender, Autodesk.Revit.UI.Events.TextBoxEnterPressedEventArgs e)
        {
            // Cast sender to TextBox to retrieve text value
            TextBox textBox = sender as TextBox;
            TaskDialog.Show("TextBox Input", "This is what you typed in: " + textBox.Value.ToString());
        }

        /// <summary>
        /// Combo box - 5 items in 2 groups. 
        /// Combo box is used in conjunction with event. We'll come back later. 
        /// For now, just demonstrates how to make a combo box. 
        /// </summary>
        public void AddComboBox(RibbonPanel panel)
        {
            // Create five combo box members with two groups 

            // #1 
            ComboBoxMemberData comboBoxMemberData1 = new ComboBoxMemberData("ComboCommandData", "Command Data");
            comboBoxMemberData1.Image = NewBitmapImage(_imageFolder);
            comboBoxMemberData1.GroupName = "DB Basics";

            // #2 
            ComboBoxMemberData comboBoxMemberData2 = new ComboBoxMemberData("ComboDbElement", "DB Element");
            comboBoxMemberData2.Image = NewBitmapImage(_imageFolder);
            comboBoxMemberData2.GroupName = "DB Basics";

            // #3 
            ComboBoxMemberData comboBoxMemberData3 = new ComboBoxMemberData("ComboElementFiltering", "Filtering");
            comboBoxMemberData3.Image = NewBitmapImage(_imageFolder);
            comboBoxMemberData3.GroupName = "DB Basics";

            // #4 
            ComboBoxMemberData comboBoxMemberData4 = new ComboBoxMemberData("ComboElementModification", "Modify");
            comboBoxMemberData4.Image = NewBitmapImage(_imageFolder);
            comboBoxMemberData4.GroupName = "Modeling";

            // #5 
            ComboBoxMemberData comboBoxMemberData5 = new ComboBoxMemberData("ComboModelCreation", "Create");
            comboBoxMemberData5.Image = NewBitmapImage(_imageFolder);
            comboBoxMemberData5.GroupName = "Modeling";

            // Make a combo box now 
            ComboBoxData comboBxData = new ComboBoxData("ComboBox");
            ComboBox comboBx = panel.AddItem(comboBxData) as ComboBox;
            comboBx.ToolTip = "Select an Option";
            comboBx.LongDescription = "select a command you want to run";
            comboBx.AddItem(comboBoxMemberData1);
            comboBx.AddItem(comboBoxMemberData2);
            comboBx.AddItem(comboBoxMemberData3);
            comboBx.AddItem(comboBoxMemberData4);
            comboBx.AddItem(comboBoxMemberData5);

            comboBx.CurrentChanged += new EventHandler<Autodesk.Revit.UI.Events.ComboBoxCurrentChangedEventArgs>(comboBx_CurrentChanged);
        }

        /// <summary>
        /// Event handler for the above combo box 
        /// </summary>    
        void comboBx_CurrentChanged(object sender, Autodesk.Revit.UI.Events.ComboBoxCurrentChangedEventArgs e)
        {
            // Cast sender as TextBox to retrieve text value
            ComboBox combodata = sender as ComboBox;
            ComboBoxMember member = combodata.Current;
            TaskDialog.Show("Combobox Selection", "Your new selection: " + member.ItemText);
        }

        /// <summary>
        /// Stacked Buttons - combination of: push button, dropdown button, combo box and text box. 
        /// (no radio button group, split buttons). 
        /// Here we stack three push buttons for "Command Data", "DB Element" and "Element Filtering". 
        /// </summary>
        public void AddStackedButtons_Simple(RibbonPanel panel)
        {
            // Create three push buttons to stack up 
            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("StackSimpleCommandData", "Command Data", _introLabPath, _introLabName + ".CommandData");
            pushButtonData1.Image = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("StackSimpleDbElement", "DB Element", _introLabPath, _introLabName + ".DBElement");
            pushButtonData2.Image = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("StackSimpleElementFiltering", "Element Filtering", _introLabPath, _introLabName + ".ElementFiltering");
            pushButtonData3.Image = NewBitmapImage(_imageFolder);

            // Put them on stack 
            IList<RibbonItem> stackedButtons = panel.AddStackedItems(pushButtonData1, pushButtonData2, pushButtonData3);
        }

        /// <summary>
        /// Stacked Buttons - combination of: push button, dropdown button, combo box and text box. 
        /// (no radio button group, split buttons). 
        /// Here we define 6 buttons, make grouping of 1, 3, 2 items, and stack them in three layer: 
        /// (1) simple push button with "Hello World" 
        /// (2) pull down with 3 items: "Command Data", "DB Element" and "Element Filtering". 
        /// (3) pull down with 2 items: "Element Modification" and "Model Creation" 
        /// </summary>
        public void AddStackedButtons_Complex(RibbonPanel panel)
        {
            // Create six push buttons to group for pull down and stack up 

            // #0 
            PushButtonData pushButtonData0 = new PushButtonData("StackComplexHelloWorld", "Hello World", _introLabPath, _introLabName + ".HelloWorld");
            pushButtonData0.Image = NewBitmapImage(_imageFolder);

            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("StackComplexCommandData", "Command Data", _introLabPath, _introLabName + ".CommandData");
            pushButtonData1.Image = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("StackComplexDbElement", "DB Element", _introLabPath, _introLabName + ".DBElement");

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("StackComplexElementFiltering", "Filtering", _introLabPath, _introLabName + ".ElementFiltering");

            // #4 
            PushButtonData pushButtonData4 = new PushButtonData("StackComplexElementModification", "Modify", _introLabPath, _introLabName + ".ElementModification");

            // #5 
            PushButtonData pushButtonData5 = new PushButtonData("StackComplexModelCreation", "Create", _introLabPath, _introLabName + ".ModelCreation");

            // Make two sets of pull down 

            PulldownButtonData pulldownBtnData1 = new PulldownButtonData("StackComplePulldownButton1", "DB Basics");
            PulldownButtonData pulldownBtnData2 = new PulldownButtonData("StackComplePulldownButton2", "Modeling");

            // Create three item stack. 
            IList<RibbonItem> stackedItems = panel.AddStackedItems(pushButtonData0, pulldownBtnData1, pulldownBtnData2);
            PulldownButton pulldownBtn2 = stackedItems[1] as PulldownButton;
            PulldownButton pulldownBtn3 = stackedItems[2] as PulldownButton;

            pulldownBtn2.Image = NewBitmapImage(_imageFolder);
            pulldownBtn3.Image = NewBitmapImage(_imageFolder);

            // Add each sub items 
            PushButton button1 = pulldownBtn2.AddPushButton(pushButtonData1);
            PushButton button2 = pulldownBtn2.AddPushButton(pushButtonData2);
            PushButton button3 = pulldownBtn2.AddPushButton(pushButtonData3);
            PushButton button4 = pulldownBtn3.AddPushButton(pushButtonData4);
            PushButton button5 = pulldownBtn3.AddPushButton(pushButtonData5);

            // Note: we need to set the image later. if we do in button data, it won't show in the Ribbon. 
            button1.Image = NewBitmapImage(_imageFolder);
            button2.Image = NewBitmapImage(_imageFolder);
            button3.Image = NewBitmapImage(_imageFolder);
            button4.Image = NewBitmapImage(_imageFolder);

            button5.Image = NewBitmapImage(_imageFolder);
        }

        /// <summary>
        /// Add buttons for the commands we define in this labs. 
        /// Here we stack three push buttons and repeat it as we get more. 
        /// This is a template to use during the Ribbon lab exercise prior to going to following labs. 
        /// </summary>
        public void AddUILabsCommandButtons_Template(RibbonPanel panel)
        {
            // Get the location of this dll. 
            string assembly = GetType().Assembly.Location;

            // Create three push buttons to stack up 
            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("UILabsCommand1", "Command1", assembly, _uiLabName + ".Command1");
            pushButtonData1.Image = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("UILabsCommand2", "Command2", assembly, _uiLabName + ".Command2");
            pushButtonData2.Image = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("UILabsCommand3", "Command3", assembly, _uiLabName + ".Command3");
            pushButtonData3.Image = NewBitmapImage(_imageFolder);

            // Put them on stack 

            IList<RibbonItem> stackedButtons = panel.AddStackedItems(pushButtonData1, pushButtonData2, pushButtonData3);
        }

        /// <summary>
        /// Add buttons for the commands we define in this labs. 
        /// Here we stack three push buttons and repeat it as we get more. 
        /// </summary>
        public void AddUILabsCommandButtons(RibbonPanel panel)
        {
            // Get the location of this dll. 
            string assembly = GetType().Assembly.Location;

            // Create three push buttons to stack up 
            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("UILabsSelection", "Pick Sampler", assembly, _uiLabName + ".UISelection");
            pushButtonData1.Image = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("UILabsCreateHouse", "Create House Pick", assembly, _uiLabName + ".UICreateHouse");
            pushButtonData2.Image = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("UILabsTaskDialog", "Dialog Sampler", assembly, _uiLabName + ".UITaskDialog");
            pushButtonData3.Image = NewBitmapImage(_imageFolder);

            // #4 
            PushButtonData pushButtonData4 = new PushButtonData("UILabsCreateHouseDialog", "Create House Dialog", assembly, _uiLabName + ".UICreateHouseDialog");
            pushButtonData4.Image = NewBitmapImage(_imageFolder);

            // #5 
            // Make three sets of pull down 
            PulldownButtonData pulldownBtnData1 = new PulldownButtonData("UILabsPulldownButton1", "Selection");
            PulldownButtonData pulldownBtnData2 = new PulldownButtonData("UILabsPulldownButton2", "Task Dialog");

            // Create three item stack. 
            IList<RibbonItem> stackedItems = panel.AddStackedItems(pulldownBtnData1, pulldownBtnData2);
            PulldownButton pulldownBtn1 = stackedItems[0] as PulldownButton;
            PulldownButton pulldownBtn2 = stackedItems[1] as PulldownButton;

            pulldownBtn1.Image = NewBitmapImage(_imageFolder);
            pulldownBtn2.Image = NewBitmapImage(_imageFolder);

            // Add each sub items 
            PushButton button1 = pulldownBtn1.AddPushButton(pushButtonData1);
            PushButton button2 = pulldownBtn1.AddPushButton(pushButtonData2);
            PushButton button3 = pulldownBtn2.AddPushButton(pushButtonData3);
            PushButton button4 = pulldownBtn2.AddPushButton(pushButtonData4);

            // Note: we need to set the image later. if we do in button data, it won't show in the Ribbon. 
            button1.Image = NewBitmapImage(_imageFolder);
            button2.Image = NewBitmapImage(_imageFolder);
            button3.Image = NewBitmapImage(_imageFolder);
            button4.Image = NewBitmapImage(_imageFolder);
        }

        /// <summary>
        /// Add buttons for the commands we define in this labs. 
        /// Here we stack 2 x 2-push buttons and repeat it as we get more. 
        /// TBD: still thinking which version is better ... 
        /// </summary>
        public void AddUILabsCommandButtons_v2(RibbonPanel panel)
        {
            // Get the location of this dll. 
            string assembly = GetType().Assembly.Location;

            // Create push buttons to stack up 
            // #1 
            PushButtonData pushButtonData1 = new PushButtonData("UILabsSelection", "Pick Sampler", assembly, _uiLabName + ".UISelection");
            pushButtonData1.Image = NewBitmapImage(_imageFolder);

            // #2 
            PushButtonData pushButtonData2 = new PushButtonData("UILabsCreateHouseUI", "Create House Pick", assembly, _uiLabName + ".CreateHouseUI");
            pushButtonData2.Image = NewBitmapImage(_imageFolder);

            // #3 
            PushButtonData pushButtonData3 = new PushButtonData("UILabsTaskDialog", "Dialog Sampler", assembly, _uiLabName + ".UITaskDialog");
            pushButtonData3.Image = NewBitmapImage(_imageFolder);

            // #4 
            PushButtonData pushButtonData4 = new PushButtonData("UILabsCreateHouseDialog", "Create House Dialog", assembly, _uiLabName + ".CreateHouseDialog");
            pushButtonData4.Image = NewBitmapImage(_imageFolder);

            // Create 2 x 2-item stack. 
            IList<RibbonItem> stackedItems1 = panel.AddStackedItems(pushButtonData1, pushButtonData2);

            IList<RibbonItem> stackedItems2 = panel.AddStackedItems(pushButtonData3, pushButtonData4);
        }

        /// <summary>
        /// Control buttons for Event and Dynamic Model Update 
        /// </summary>
        public void AddUILabsCommandButtons2(RibbonPanel panel)
        {
            // Get the location of this dll. 
            string assembly = GetType().Assembly.Location;

            // Create three toggle buttons for radio button group 
            // #1 
            ToggleButtonData toggleButtonData1 = new ToggleButtonData("UILabsEventOn", "Event" + "\n Off", assembly, _uiLabName + ".UIEventOff");
            toggleButtonData1.LargeImage = NewBitmapImage(_imageFolder);

            // #2 
            ToggleButtonData toggleButtonData2 = new ToggleButtonData("UILabsEventOff", "Event" + "\n On", assembly, _uiLabName + ".UIEventOn");
            toggleButtonData2.LargeImage = NewBitmapImage(_imageFolder);

            // Create three toggle buttons for radio button group 
            // #3 
            ToggleButtonData toggleButtonData3 = new ToggleButtonData("UILabsDynUpdateOn", "Center" + "\n Off", assembly, _uiLabName + ".UIDynamicModelUpdateOff");
            toggleButtonData3.LargeImage = NewBitmapImage(_imageFolder);

            // #4 
            ToggleButtonData toggleButtonData4 = new ToggleButtonData("UILabsDynUpdateOff", "Center" + "\n On", assembly, _uiLabName + ".UIDynamicModelUpdateOn");
            toggleButtonData4.LargeImage = NewBitmapImage(_imageFolder);

            // Make event pn/off radio button group 
            RadioButtonGroupData radioBtnGroupData1 = new RadioButtonGroupData("EventNotification");
            RadioButtonGroup radioBtnGroup1 = panel.AddItem(radioBtnGroupData1) as RadioButtonGroup;
            radioBtnGroup1.AddItem(toggleButtonData1);
            radioBtnGroup1.AddItem(toggleButtonData2);

            // Make dyn update on/off radio button group 
            RadioButtonGroupData radioBtnGroupData2 = new RadioButtonGroupData("WindowDoorCenter");
            RadioButtonGroup radioBtnGroup2 = panel.AddItem(radioBtnGroupData2) as RadioButtonGroup;
            radioBtnGroup2.AddItem(toggleButtonData3);

            radioBtnGroup2.AddItem(toggleButtonData4);
        }
    }

    #region Helper Classes
    /// <summary>
    /// This lab uses Revit Intro Labs. 
    /// If you prefer to use a dummy command instead, you can do so. 
    /// Providing a command template here. 
    /// </summary>
    [Transaction(TransactionMode.Automatic)]
    public class DummyCommand1 : IExternalCommand
    {
        public Result Execute(
          ExternalCommandData commandData,
          ref string message,
          ElementSet elements)
        {
            // Write your command implementation here 

            TaskDialog.Show("Dummy command", "You have called Command1");

            return Result.Succeeded;
        }
    }
    #endregion
}

